/* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
   Module Name          : com.yaodian100.crm.workorder.service.impl.WorkOrderServiceImpl
   Module Description   :

   Date Created      : 2009/12/17
   Original Author   : andy.chuang
   Team              : yaodian100
   ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
   MODIFICATION HISTORY
   ------------------------------------------------------------------------------
   Date Modified       Modified by       Comments
   ------------------------------------------------------------------------------
   ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
package com.yaodian100.crm.workorder.service.impl;

import java.io.ByteArrayOutputStream;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import org.apache.commons.betwixt.io.BeanWriter;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.time.FastDateFormat;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.security.userdetails.UserDetails;
import org.springframework.transaction.annotation.Transactional;

import com.yaodian100.core.admin.entity.Group;
import com.yaodian100.core.admin.entity.User;
import com.yaodian100.core.admin.utils.AdminHelper;
import com.yaodian100.core.batch.service.BatchJobService;
import com.yaodian100.core.common.exception.CoreException;
import com.yaodian100.core.common.service.BaseManager;
import com.yaodian100.core.common.utils.JspUtil;
import com.yaodian100.core.common.utils.ServerValue;
import com.yaodian100.core.form.entity.Attribute;
import com.yaodian100.core.logger.service.LogService;
import com.yaodian100.core.mail.entity.Mail;
import com.yaodian100.core.mail.service.MailService;
import com.yaodian100.core.sms.service.SmsService;
import com.yaodian100.core.template.service.TemplateService;
import com.yaodian100.crm.cs.entity.Answer;
import com.yaodian100.crm.cs.entity.CommonQuestionType;
import com.yaodian100.crm.cs.entity.GroupContactWindow;
import com.yaodian100.crm.cs.entity.Question;
import com.yaodian100.crm.cs.entity.QuestionExtraValue;
import com.yaodian100.crm.workflow.entity.WorkFlow;
import com.yaodian100.crm.workflow.entity.WorkFlowNode;
import com.yaodian100.crm.workorder.entity.TaskGroup;
import com.yaodian100.crm.workorder.entity.TaskGroupUser;
import com.yaodian100.crm.workorder.entity.WorkOrder;
import com.yaodian100.crm.workorder.entity.WorkOrderApprove;
import com.yaodian100.crm.workorder.rule.WorkOrderRule;
import com.yaodian100.crm.workorder.service.WorkOrderService;
import com.yaodian100.ec.common.EcConstant;
import com.yaodian100.ec.common.EnvParameters;
import com.yaodian100.ec.member.entity.Balance;
import com.yaodian100.ec.member.entity.Member;
import com.yaodian100.ec.member.service.MemberService;
import com.yaodian100.ec.order.entity.OrderProduct;
import com.yaodian100.ec.order.entity.Orders;
import com.yaodian100.ec.order.entity.ServiceOrders;
import com.yaodian100.ec.product.entity.Product;
import com.yaodian100.ec.product.service.OrderCommentService;

/**
 * @author andy.chuang
 * 
 */
public class WorkOrderServiceImpl implements WorkOrderService {
	private static Logger LOGGER = LoggerFactory.getLogger(WorkOrderServiceImpl.class);
	@Resource
	private BaseManager baseMgr;
	@Resource
	private MemberService memberService;
	@Resource
	private BatchJobService batchJobService;
	@Resource
	private TemplateService velocityService;
	@Resource
	private MailService mailService;
	@Resource
	private EnvParameters envParameters;
	@Resource
	private LogService logService;
	@Autowired
	private JdbcTemplate jdbcTemplate;
	@Autowired
	private SmsService smsService;
	@Autowired
	private OrderCommentService orderCommentService;

	private TaskGroupUser getTaskGroupUserByUsername(String userName) {
		Object[] taskGroupUsers = baseMgr.queryByHql("from TaskGroupUser where user.username=?", new Object[] { userName });
		TaskGroupUser taskGroupUser = null;
		for (Object obj : taskGroupUsers) {
			TaskGroupUser theTaskGroupUser = (TaskGroupUser) obj;
			if (theTaskGroupUser.getDefaultGroup()) {
				taskGroupUser = theTaskGroupUser;
			}
		}
		if (taskGroupUser == null) {
			for (Object obj : taskGroupUsers) {
				TaskGroupUser theTaskGroupUser = (TaskGroupUser) obj;
				if (theTaskGroupUser.getTaskRole().equals(TaskGroup.GROUP_ROLE.MANAGER.getValue())
						|| theTaskGroupUser.getTaskRole().equals(TaskGroup.GROUP_ROLE.MEMBER.getValue())) {
					taskGroupUser = theTaskGroupUser;
				}
			}
		}
		if (taskGroupUser == null) {
			for (Object obj : taskGroupUsers) {
				TaskGroupUser theTaskGroupUser = (TaskGroupUser) obj;
				taskGroupUser = theTaskGroupUser;
				break;
			}
		}
		return taskGroupUser;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.yaodian100.crm.workorder.service.WorkOrderService#createWorkOrder()
	 */
	@Override
	@Transactional(readOnly = false)
	public WorkOrder createWorkOrder(String userName, String questionId, String questionShortDesc, boolean needApprove,
			User owner) {
		TaskGroupUser taskGroupUser = getTaskGroupUserByUsername(userName);

		WorkOrder wo = new WorkOrder();
		Date createDate = new Date();
		if (taskGroupUser != null) {
			wo.setCreateGroup(taskGroupUser.getTaskGroup().getId());
		}
		wo.setCreateDate(createDate);
		wo.setCreateUser(userName);
		wo.setDomainId(questionId);
		wo.setModifyUser(userName);
		if (owner != null) {
			wo.setOwner(owner);
			wo.setResponseGroup(owner.getGroupName());
		}
		wo.setStatus(0);
		if (needApprove) {
			wo.setApproveStatus(0);
		} else {
			// 不需审核，直接设定审核时间
			wo.setApproveTime(createDate);
		}
		wo.setShortDesc(questionShortDesc);
		baseMgr.save(wo);

		return wo;
	}

	@Override
	@Transactional(readOnly = false)
	public void forwardOrder(String id, String comment, String responser, String workFlowNodeId, Integer priority,
			String class1, String class2, String commonQuestionType, String mustInquire, String answer,
			String showOnProductPage) {
		// WorkOrder workOrder=(WorkOrder)baseMgr.get(WorkOrder.class, Long.parseLong(id));
		WorkOrder woPre = (WorkOrder) baseMgr.get(WorkOrder.class, Long.parseLong(id));
		Question question = (Question) baseMgr.get(Question.class, woPre.getDomainId());
		Map<String, QuestionExtraValue> valueMap = question.getExtraValue();
		List<Attribute> attrs = question.getType().getExtraAttr().getAttributes();
		for (int i = 0; i < attrs.size(); i++) {
			Attribute attr = attrs.get(i);
			QuestionExtraValue ea = valueMap.get(attr.getName());
			if (ea == null) {
				ea = new QuestionExtraValue();
			}
			ea.setQuestion(question);
			ea.setName(attr.getName());
			ea.setAttribute(attr);

			if (ea.getName().equals("class1")) {
				ea.setValue(class1);
			} else if (ea.getName().equals("class2")) {
				ea.setValue(class2);
			} else if (ea.getName().equals("commonQuestionType")) {
				ea.setValue(commonQuestionType);
			} else if (ea.getName().equals("mustInquire")) {
				ea.setValue(mustInquire);
			} else {
				continue;
			}

			baseMgr.saveOrUpdate(ea);
		}
		Date currentDate = new Date();

		baseMgr.update(question);

		// WorkOrder woPre=(WorkOrder)baseMgr.get(WorkOrder.class, Long.parseLong(id));
		UserDetails user = AdminHelper.getUserDetails();
		TaskGroupUser taskGroupUser = getTaskGroupUserByUsername(user.getUsername());
		Date createDate = new Date();
		WorkOrder wo = new WorkOrder();
		if (taskGroupUser != null) {
			wo.setCreateGroup(taskGroupUser.getTaskGroup().getId());
		}
		// WorkOrderType wot=new WorkOrderType();
		// wot.setId("CS");
		// wo.setWorkOrderType(wot);
		wo.setCreateDate(createDate);
		wo.setCreateUser(user.getUsername());
		// Question question=(Question)baseMgr.get(Question.class, woPre.getDomainId());
		question.setStatus(1);// processing
		baseMgr.update(question);
		wo.setDomainId(woPre.getDomainId());
		wo.setModifyUser(user.getUsername());
		wo.setStatus(0);
		wo.setShortDesc(woPre.getShortDesc());
		wo.setParent(woPre);
		wo.setComment(comment);
		if (null != responser) {
			User owner = (User) baseMgr.get(User.class, responser);
			wo.setOwner(owner);
		}
		wo.setPriority(priority);
		WorkFlowNode workFlowNode = (WorkFlowNode) baseMgr.get(WorkFlowNode.class, workFlowNodeId);
		wo.setNode(workFlowNode);
		wo.setApproveGroup(workFlowNode.getApproveGroup());
		wo.setResponseGroup(workFlowNode.getResponseGroup());

		if (workFlowNode.getNeedApprove()) {
			if (workFlowNode.getBeApprovedGroup() != null && !workFlowNode.getBeApprovedGroup().equals("")) {
				// 有特定需被审核的群组
				Group userGroup = JspUtil.getGroupByUsername(user.getUsername());
				if (userGroup.getCode().equals(workFlowNode.getBeApprovedGroup())) {
					wo.setApproveStatus(WorkOrder.APPROVE_STATUS.INIT.value());
					wo.setApprover(workFlowNode.getApprover());
					wo.setApproveGroup(workFlowNode.getApproveGroup());
				}
			} else {
				wo.setApproveStatus(WorkOrder.APPROVE_STATUS.INIT.value());
				wo.setApprover(workFlowNode.getApprover());
				wo.setApproveGroup(workFlowNode.getApproveGroup());
			}
		}
		woPre.setStatus(WorkOrder.STATUS.FORWARDED.value());
		// answer
		if (answer != null && answer.trim().length() > 0) {
			if (WorkOrderRule.answerNeedToBeApproved(woPre)) {
				woPre.setApproveGroup(WorkOrderRule.line2);
				woPre.setApproveStatus(WorkOrder.APPROVE_STATUS.INIT.value());
				woPre.setStatus(WorkOrder.STATUS.ANSWER_NEED_CONFIRM.value());
				wo.setStatus(WorkOrder.STATUS.NOT_ACTIVE.value());
				answered(answer, showOnProductPage, currentDate, question, true, woPre);
			} else {
				answered(answer, showOnProductPage, currentDate, question, false, woPre);
			}
		}
		baseMgr.save(wo);

		baseMgr.update(woPre);
		forwardOrderNotice(wo);
	}

	private void updateMemberBalance(Question question) {
		if (question.getType().getName().equals("CommonQuestion") && question.getMemberId() != null) {
			Balance balance = (Balance) baseMgr.get(Balance.class, question.getMemberId());
			if (balance == null) {
				return;
			}
			// refresh member balance
			if (question.getExtraValue().get("isProductQAA") == null
					|| question.getExtraValue().get("isProductQAA").getValue().equals("false")) {

				Calendar calendar = Calendar.getInstance();
				calendar.add(Calendar.DAY_OF_MONTH, -14);
				// 客服问答 两周内已回答
				String hql = "from Question q where q.memberId=? and q.type.name=? and q.answeredDate>=? and q.extraValue['isProductQAA'].value=?";
				List<Object> params = new ArrayList<Object>();
				params.add(question.getMemberId());
				params.add("CommonQuestion");
				params.add(calendar.getTime());
				params.add("false");

				Long count = baseMgr.countByHql(hql, params.toArray());
				balance.setRepliedCRM(new BigDecimal(count));
				// 客服問答 發問中
				hql = "from Question q where q.memberId=? and q.type.name=? and q.answeredDate is null and q.extraValue['isProductQAA'].value=?";
				params = new ArrayList<Object>();
				params.add(question.getMemberId());
				params.add("CommonQuestion");
				params.add("false");
				Long countQ = baseMgr.countByHql(hql, params.toArray());
				balance.setAskedCRM(new BigDecimal(countQ));

			} else if (question.getExtraValue().get("isProductQAA") != null
					&& question.getExtraValue().get("isProductQAA").getValue().equals("true")) {
				Calendar calendar = Calendar.getInstance();
				calendar.add(Calendar.DAY_OF_MONTH, -14);
				// 商品问答 两周内已回答
				String hql = "from Question q where q.memberId=? and q.type.name=? and q.answeredDate>=? and q.extraValue['isProductQAA'].value=?";
				List<Object> params = new ArrayList<Object>();
				params.add(question.getMemberId());
				params.add("CommonQuestion");
				params.add(calendar.getTime());
				params.add("true");

				Long count = baseMgr.countByHql(hql, params.toArray());

				balance.setRepliedProductQuestion(new BigDecimal(count));

				// 商品问答 发问中
				hql = "from Question q where q.memberId=? and q.type.name=? and q.answeredDate is null and q.extraValue['isProductQAA'].value=?";
				params = new ArrayList<Object>();
				params.add(question.getMemberId());
				params.add("CommonQuestion");
				params.add("true");

				Long countQ = baseMgr.countByHql(hql, params.toArray());
				balance.setAskedProductQuestion(new BigDecimal(countQ));

			}
			memberService.saveOrUpdateBalance(balance);
		}
	}

	@Override
	@Transactional(readOnly = false)
	public WorkOrder forwardOrder(WorkOrder woPre, String comment, String responser, String workFlowNodeId,
			Integer priority) {
		UserDetails user = AdminHelper.getUserDetails();

		if (user == null) {
			user = (User) baseMgr.get(User.class, responser);
		}
		TaskGroupUser taskGroupUser = getTaskGroupUserByUsername(user.getUsername());
		Date createDate = new Date();
		WorkOrder wo = new WorkOrder();
		if (taskGroupUser != null) {
			wo.setCreateGroup(taskGroupUser.getTaskGroup().getId());
		}
		// WorkOrderType wot=new WorkOrderType();
		// wot.setId("CS");
		// wo.setWorkOrderType(wot);
		wo.setCreateDate(createDate);
		wo.setCreateUser(user.getUsername());
		Question question = (Question) baseMgr.get(Question.class, woPre.getDomainId());
		question.setStatus(1);// processing
		baseMgr.update(question);
		wo.setQuestion(question);
		wo.setDomainId(woPre.getDomainId());
		wo.setModifyUser(user.getUsername());
		wo.setStatus(0);
		wo.setShortDesc(woPre.getShortDesc());
		wo.setParent(woPre);
		wo.setComment(comment);
		User owner = null;
		TaskGroupUser theTu = null;

		if (responser != null) {
			owner = (User) baseMgr.get(User.class, responser);
			if (owner == null) {
				owner = (User) baseMgr.get(User.class, responser.toLowerCase());
			}
			wo.setOwner(owner);
			Object[] gus = baseMgr.queryByHql("from TaskGroupUser where user.username=?", new Object[] { responser });

			if (gus != null) {
				for (int i = 0; i < gus.length; i++) {
					TaskGroupUser tu = (TaskGroupUser) gus[i];
					if (tu.getDefaultGroup()) {
						theTu = tu;
					}
				}
				if (theTu == null && gus.length > 0) {
					theTu = (TaskGroupUser) gus[0];
				}
			}

		}
		wo.setPriority(priority);
		WorkFlowNode workFlowNode = (WorkFlowNode) baseMgr.get(WorkFlowNode.class, workFlowNodeId);
		wo.setNode(workFlowNode);

		wo.setResponseGroup(workFlowNode.getResponseGroup());
		if (theTu != null) {
			wo.setResponseGroup(theTu.getTaskGroup().getId());
		}

		// 断缺货工单不写responer
		if (wo.getQuestion().getType().equals("OutOfStock")) {
			wo.setResponseGroup(null);
			wo.setOwner(null);
		}
		// 配送商特殊作法
		if (owner != null && question.getType().getName().equals("AskDeliver")) {
			wo.setResponseGroup(owner.getGroupName());
			wo.setOwner(null);
		}

		if (workFlowNode.getNeedApprove()) {
			if (workFlowNode.getBeApprovedGroup() != null && !workFlowNode.getBeApprovedGroup().equals("")) {
				// 有特定需被审核的群组
				Group userGroup = JspUtil.getGroupByUsername(user.getUsername());
				if (userGroup.getCode().equals(workFlowNode.getBeApprovedGroup())) {
					wo.setApproveStatus(WorkOrder.APPROVE_STATUS.INIT.value());
					wo.setApprover(workFlowNode.getApprover());
					wo.setApproveGroup(workFlowNode.getApproveGroup());
				}
			} else {
				wo.setApproveStatus(WorkOrder.APPROVE_STATUS.INIT.value());
				wo.setApprover(workFlowNode.getApprover());
				wo.setApproveGroup(workFlowNode.getApproveGroup());
			}
		}
		baseMgr.save(wo);

		woPre.setStatus(3);
		baseMgr.update(woPre);
		forwardOrderNotice(wo);
		return wo;
	}

	@Override
	@Transactional(readOnly = false)
	public WorkOrder forwardOrder(WorkOrder woPre, String comment, String creater, String responseGroup,
			String workFlowNodeId, Integer priority) {
		User createUser = null;
		createUser = (User) baseMgr.get(User.class, creater);

		TaskGroupUser taskGroupUser = getTaskGroupUserByUsername(createUser.getUsername());
		Date createDate = new Date();
		WorkOrder wo = new WorkOrder();
		if (taskGroupUser != null) {
			wo.setCreateGroup(taskGroupUser.getTaskGroup().getId());
		}
		// WorkOrderType wot=new WorkOrderType();
		// wot.setId("CS");
		// wo.setWorkOrderType(wot);
		wo.setCreateDate(createDate);
		wo.setCreateUser(createUser.getUsername());
		Question question = (Question) baseMgr.get(Question.class, woPre.getDomainId());
		question.setStatus(1);// processing
		baseMgr.update(question);
		wo.setDomainId(woPre.getDomainId());
		wo.setModifyUser(createUser.getUsername());
		wo.setStatus(0);
		wo.setShortDesc(woPre.getShortDesc());
		wo.setParent(woPre);
		wo.setComment(comment);

		wo.setPriority(priority);
		WorkFlowNode workFlowNode = (WorkFlowNode) baseMgr.get(WorkFlowNode.class, workFlowNodeId);
		wo.setNode(workFlowNode);

		wo.setResponseGroup(workFlowNode.getResponseGroup());

		if (responseGroup != null) {
			wo.setResponseGroup(responseGroup);
		}

		if (workFlowNode.getNeedApprove()) {
			if (workFlowNode.getBeApprovedGroup() != null && !workFlowNode.getBeApprovedGroup().equals("")) {
				// 有特定需被审核的群组
				if (responseGroup != null && responseGroup.equals(workFlowNode.getBeApprovedGroup())) {
					wo.setApproveStatus(WorkOrder.APPROVE_STATUS.INIT.value());
					wo.setApprover(workFlowNode.getApprover());
					wo.setApproveGroup(workFlowNode.getApproveGroup());
				}
			} else {
				wo.setApproveStatus(WorkOrder.APPROVE_STATUS.INIT.value());
				wo.setApprover(workFlowNode.getApprover());
				wo.setApproveGroup(workFlowNode.getApproveGroup());
			}
		}
		baseMgr.save(wo);

		woPre.setStatus(3);
		baseMgr.update(woPre);
		if (!question.getType().getName().equals("CheckMobile")) {
			forwardOrderNotice(wo);
		}
		return wo;
	}

	@Override
	@Transactional(readOnly = false)
	public WorkOrder forwardOrder(String id, String comment, String responser, String workFlowNodeId, Integer priority) {
		WorkOrder woPre = (WorkOrder) baseMgr.get(WorkOrder.class, Long.parseLong(id));
		return forwardOrder(woPre, comment, responser, workFlowNodeId, priority);
	}

	@Override
	@Transactional(readOnly = false)
	public WorkOrder forwardOrderForRemote(String id, String comment, String creater, String responser,
			String workFlowNodeId, Integer priority) {
		WorkOrder woPre = (WorkOrder) baseMgr.get(WorkOrder.class, Long.parseLong(id));
		return forwardOrder(woPre, comment, creater, responser, workFlowNodeId, priority);
	}

	private void sendReturnMail(WorkOrder wo) {
		if (wo.getStatus() == WorkOrder.STATUS.RETURNED.value()) {
			Map<String, Object> objs = new HashMap<String, Object>();
			objs.put("domainId", wo.getQuestion().getId());
			objs.put("", wo.getId());
			objs.put("midendUrl", ServerValue.getMidHostname() + ServerValue.getMidContextPath());
			String subject = "「問題編號：" + wo.getQuestion().getId() + "」轉單已回覆";
			String body = wo.getComment();
			User user = wo.getOwner();
			String to = "";
			if (user != null) {
				to = user.getEmail();
			} else {
				return;
			}
			Mail entity = new Mail(subject, body, to, null);

			mailService.save(entity);
		}

	}

	private void forwardOrderNotice(WorkOrder wo) {

		if (wo.getResponseGroup() == null) {
			return;
		}
		GroupContactWindow gcw = (GroupContactWindow) baseMgr.get(GroupContactWindow.class, wo.getResponseGroup());
		if (gcw == null || gcw.getToMail() == null) {
			return;
		}
		// 工单不再用group，而是用taskgroup
		// Group group = (Group) baseMgr.get(Group.class, gcw.getGroupId());
		TaskGroup group = (TaskGroup) baseMgr.get(TaskGroup.class, gcw.getGroupId());

		if (wo.getApproveStatus() == WorkOrder.APPROVE_STATUS.APPROVED.value()) {// 狀態是審核通過才要寄信
			// 发送缺货通知信
			Question question = (Question) baseMgr.get(Question.class, wo.getDomainId());
			Map<String, Object> objs = new HashMap<String, Object>();
			objs.put("question", question);
			objs.put("groupName", group.getName());
			objs.put("workOrderId", wo.getId());
			objs.put("midendUrl", ServerValue.getMidHostname() + ServerValue.getMidContextPath());

			Mail entity = velocityService.formatToMail("workOrderForward", objs);
			String[] toMails = gcw.getToMail().split(",");
			for (String toMail : toMails) {
				entity.addTo(toMail, toMail);
			}
			if (gcw.getCcMail() != null) {
				String[] ccMails = gcw.getCcMail().split(",");
				for (String ccMail : ccMails) {
					entity.addCc(ccMail, ccMail);
				}
			}
			entity.setFrom(envParameters.getEmailFromCs());
			mailService.save(entity);

		}
	}

	@Override
	@Transactional(readOnly = false)
	public void backwardOrder(String id, String comment, String responser, String workFlowNodeId, Integer priority,
			String class1, String class2, String commonQuestionType, String mustInquire, String answer,
			String showOnProductPage) {
		// WorkOrder workOrder=(WorkOrder)baseMgr.get(WorkOrder.class, Long.parseLong(id));
		WorkOrder woPre = (WorkOrder) baseMgr.get(WorkOrder.class, Long.parseLong(id));
		Question question = (Question) baseMgr.get(Question.class, woPre.getDomainId());
		Map<String, QuestionExtraValue> valueMap = question.getExtraValue();
		List<Attribute> attrs = question.getType().getExtraAttr().getAttributes();
		for (int i = 0; i < attrs.size(); i++) {
			Attribute attr = attrs.get(i);
			QuestionExtraValue ea = valueMap.get(attr.getName());
			if (ea == null) {
				ea = new QuestionExtraValue();
			}
			ea.setQuestion(question);
			ea.setName(attr.getName());
			ea.setAttribute(attr);

			if (ea.getName().equals("class1")) {
				ea.setValue(class1);
			} else if (ea.getName().equals("class2")) {
				ea.setValue(class2);
			} else if (ea.getName().equals("commonQuestionType")) {
				ea.setValue(commonQuestionType);
			} else if (ea.getName().equals("mustInquire")) {
				ea.setValue(mustInquire);
			} else {
				continue;
			}

			baseMgr.saveOrUpdate(ea);
		}

		// WorkOrder woPre=(WorkOrder)baseMgr.get(WorkOrder.class, Long.parseLong(id));
		UserDetails user = AdminHelper.getUserDetails();
		TaskGroupUser taskGroupUser = getTaskGroupUserByUsername(user.getUsername());
		Date createDate = new Date();
		WorkOrder wo = new WorkOrder();
		if (taskGroupUser != null) {
			wo.setCreateGroup(taskGroupUser.getTaskGroup().getId());
		}
		// WorkOrderType wot=new WorkOrderType();
		// wot.setId("CS");
		// wo.setWorkOrderType(wot);
		wo.setCreateDate(createDate);
		wo.setCreateUser(user.getUsername());
		// Question question=(Question)baseMgr.get(Question.class, woPre.getDomainId());
		question.setStatus(1);// processing
		baseMgr.update(question);
		wo.setDomainId(woPre.getDomainId());
		wo.setModifyUser(user.getUsername());
		wo.setStatus(0);
		wo.setShortDesc(woPre.getShortDesc());
		wo.setParent(woPre);
		wo.setComment(comment);
		User owner = (User) baseMgr.get(User.class, responser);
		wo.setOwner(owner);
		wo.setPriority(priority);

		WorkFlowNode workFlowNode = null;
		if (workFlowNodeId != null && workFlowNodeId.length() > 0) {
			workFlowNode = (WorkFlowNode) baseMgr.get(WorkFlowNode.class, workFlowNodeId);
			if (workFlowNode.getNeedApprove()) {
				wo.setApproveStatus(WorkOrder.APPROVE_STATUS.INIT.value());
				wo.setApprover(workFlowNode.getApprover());
			}
		}
		wo.setNode(workFlowNode);
		woPre.setStatus(WorkOrder.STATUS.FORWARDED.value());
		// answer
		Date currentDate = new Date();
		if (answer != null) {
			if (WorkOrderRule.answerNeedToBeApproved(woPre)) {
				woPre.setApproveGroup(WorkOrderRule.line2);
				woPre.setApproveStatus(WorkOrder.APPROVE_STATUS.INIT.value());
				woPre.setStatus(WorkOrder.STATUS.ANSWER_NEED_CONFIRM.value());
				wo.setStatus(WorkOrder.STATUS.NOT_ACTIVE.value());
				answered(answer, showOnProductPage, currentDate, question, true, woPre);
			} else {
				answered(answer, showOnProductPage, currentDate, question, false, woPre);
			}

		}
		baseMgr.update(question);

		baseMgr.save(wo);

		baseMgr.update(woPre);
		forwardOrderNotice(wo);
	}

	private void answered(String answer, String showOnProductPage, Date currentDate, Question question,
			Boolean needApprove, WorkOrder workOrder) {
		if (answer == null || answer.trim().length() == 0) {
			return;
		}
		Answer theAnswer = new Answer();
		if (needApprove != null && needApprove) {
			theAnswer.setIsApproved(false);
		}
		theAnswer.setWorkOrder(workOrder);
		theAnswer.setCreateUser(AdminHelper.getUserDetails().getUsername());
		theAnswer.setContent(answer);
		if (showOnProductPage != null && showOnProductPage.length() > 0) {
			theAnswer.setShowOnProductPage(Boolean.parseBoolean(showOnProductPage));
		}
		theAnswer.setCreateDate(currentDate);
		theAnswer.setModifyUser(theAnswer.getCreateUser());
		theAnswer.setQuestion(question);
		theAnswer.setTitle(question.getShortDesc());
		baseMgr.save(theAnswer);
		if (question.getAnswer() == null) {
			question.setAnsweredDate(currentDate);
			question.setAnswer(theAnswer);
			updateMemberBalance(question);
		}
		if (theAnswer.getIsApproved() == null || theAnswer.getIsApproved()) {
			sendMailForAnswer(question, theAnswer);
		}
	}

	@Transactional(readOnly = false)
	private void sendMailForAnswer(Question question, Answer theAnswer) {
		Map<String, Object> objs = new HashMap<String, Object>();
		if (question.getExtraValue().get("isProductQAA") != null
				&& question.getExtraValue().get("isProductQAA").getValue() != null) {
			if (question.getExtraValue().get("isProductQAA").getValue().equals("false")) {
				// 客服問答
				String class2 = question.getExtraValue().get("class2").getValue();
				if (class2 != null) {
					CommonQuestionType cqt = (CommonQuestionType) baseMgr.get(CommonQuestionType.class, class2);
					objs.put("class2", cqt.getName());
				} else {
					objs.put("class2", " ");
				}

				String memberName = "顾客";
				String domainSrc = "www.yaodian100.com";
				SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
				Member member = null;
				if (question.getMemberId() != null) {
					member = (Member) baseMgr.get(Member.class, question.getMemberId());
					if (member != null) {
						memberName = member.getLoginId();
						domainSrc = member.getDomainSrc();
					}
				}
				objs.put("memberName", memberName);
				objs.put("question", question.getDescription());
				objs.put("answer", theAnswer.getContent());
				objs.put("questionId", question.getId());
				objs.put("questionDate", sdf.format(question.getCreateDate()));
				if (question.getExtraValue().get("productId") != null) {
					objs.put("orderOrProduct", "商品编号：<a href=\"" + ServerValue.getFrontHostname()
							+ "/ecmall/product/product.do?productId=" + question.getExtraValue().get("productId").getValue() + "\">"
							+ question.getExtraValue().get("productId").getValue() + "</a>");
				} else if (question.getExtraValue().get("orderId") != null) {
					objs.put("orderOrProduct", "订单编号：<a href=\"" + ServerValue.getFrontHostname()
							+ "/ecmall/member/order/page.do?detail&orderId=" + question.getExtraValue().get("orderId").getValue()
							+ "\">" + question.getExtraValue().get("orderId").getValue() + "</a>");
				}
				objs.put("basehref", "http://" + domainSrc);
				objs.put("domainSrc", domainSrc);
				if (member != null && member.getEmail() != null) {
					Mail entity = velocityService.formatToMail("service_qa_respond", objs);
					entity.addTo(memberName, member.getEmail());
					entity.setFrom(envParameters.getEmailFromCs());
					mailService.save(entity);
				}
			} else {
				// 商品問答
				SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
				objs.put("basehref", "http://www.yaodian100.com");
				String memberName = "顾客";
				String email = question.getEmail();
				if (question.getMemberId() != null) {
					Member member = (Member) baseMgr.get(Member.class, question.getMemberId());
					if (member != null) {
						memberName = member.getLoginId();
						email = member.getEmail();
						objs.put("domainSrc", member.getDomainSrc());
						objs.put("basehref", "http://" + member.getDomainSrc());
					} else {
						objs.put("domainSrc", "www.yaodian100.com");
					}
				}
				objs.put("memberName", memberName);
				objs.put("question", question.getDescription());
				objs.put("answer", theAnswer.getContent());
				objs.put("questionId", question.getId());
				String productId = question.getExtraValue().get("productId").getValue();
				objs.put("productId", productId);
				Product product = null;
				if (productId != null) {
					product = (Product) baseMgr.get(Product.class, productId);
					if (product != null) {
						objs.put("productName", product.getProductName());
					}
				}
				objs.put("questionDate", sdf.format(question.getCreateDate()));
				objs.put("answerDate", sdf.format(theAnswer.getCreateDate()));
				if (product != null && email != null) {
					if (theAnswer.getShowOnProductPage() != null && theAnswer.getShowOnProductPage()) {
						Mail entity = velocityService.formatToMail("myorder_pd_public_replied", objs);
						entity.addTo(memberName, email);
						entity.setFrom(envParameters.getEmailFromCs());
						mailService.save(entity);
					} else {
						Mail entity = velocityService.formatToMail("myorder_pd_private_replied", objs);
						entity.addTo(memberName, email);
						entity.setFrom(envParameters.getEmailFromCs());
						mailService.save(entity);
					}
				}

			}
		}
	}

	@Override
	@Transactional(readOnly = false)
	public void closeOrder(String id, String answer, String showOnProductPage, String workOrderId, String note,
			String finishType, String endPriority, String endClass1, String endClass2, String endClass3) {
		this.closeOrder(id, answer, showOnProductPage, workOrderId, note, finishType, endPriority, endClass1, endClass2,
				endClass3, null);
	}

	@Override
	@Transactional(readOnly = false)
	public void closeOrder(String id, String answer, String showOnProductPage, String workOrderId, String note,
			String finishType, String endPriority, String endClass1, String endClass2, String endClass3, String compensation) {
		closeOrderReturnWorkOrder(id, answer, showOnProductPage, workOrderId, note, finishType, endPriority, endClass1,
				endClass2, endClass3, compensation);
	}

	@Override
	@Transactional(readOnly = false)
	public void closeProductCommentOrder(String id, String answer, String showOnProductPage, String workOrderId,
			String note, String finishType, String endPriority, String endClass1, String endClass2, String endClass3,
			String compensation, String type) throws NumberFormatException, Exception {
		WorkOrder wo = closeOrderReturnWorkOrder(id, answer, showOnProductPage, workOrderId, note, finishType, endPriority,
				endClass1, endClass2, endClass3, compensation);
		orderCommentService.approveOrderCommentByWorkorder(wo.getQuestion().getExtraValue().get("commentId").getValue(),
				type, note);
	}

	@Override
	@Transactional(readOnly = false)
	public void closeProductCommentOrderFromCM(String commentId, String reason) {
		String questionId = "";
		String woId = "";
		String sql = "select cqe.question_id, cwo.work_order_id from crm_question_ev cqe, crm_work_order cwo "
				+ "where cqe.value = '" + commentId + "' and cqe.name = 'commentId' "
				+ "and cwo.domainid = cqe.question_id and cwo.status not in (2,3)";
		List<Map<String, Object>> qList = jdbcTemplate.queryForList(sql);
		if (null == qList || qList.isEmpty()) {
			return;
		}
		questionId = qList.get(0).get("QUESTION_ID").toString();
		woId = qList.get(0).get("WORK_ORDER_ID").toString();
		closeOrderReturnWorkOrder(questionId, reason, "false", woId, reason, WorkOrder.FINISH_TYPE.SELF.value(), null, "",
				"", "", null);
	}

	@Transactional(readOnly = false)
	public WorkOrder closeOrderReturnWorkOrder(String id, String answer, String showOnProductPage, String workOrderId,
			String note, String finishType, String endPriority, String endClass1, String endClass2, String endClass3,
			String compensation) {
		try {
			Date currentDate = new Date();
			Question question = (Question) baseMgr.get(Question.class, id);
			System.out.println("question:" + question);
			WorkOrder wo = (WorkOrder) baseMgr.get(WorkOrder.class, Long.parseLong(workOrderId));
			if (wo.getOwner() == null) {
				User user = AdminHelper.getUser();
				wo.setOwner(user);
				wo.setStartTime(new Date());
			}
			wo.setFinishType(finishType);
			wo.setNote(note);
			wo.setFinishTime(currentDate);
			if (endPriority != null) {
				wo.setEndPriority(Integer.valueOf(endPriority));
			} else {
				wo.setEndPriority(wo.getPriority());
			}
			if (endClass1 == null) {
				QuestionExtraValue evClass = wo.getQuestion().getExtraValue().get("class1");
				if (evClass != null) {
					wo.setEndClass1(evClass.getValue());
				}
			} else {
				wo.setEndClass1(endClass1);
			}
			if (endClass2 == null) {
				QuestionExtraValue evClass = wo.getQuestion().getExtraValue().get("class2");
				if (evClass != null) {
					wo.setEndClass2(evClass.getValue());
				}
			} else {
				wo.setEndClass2(endClass2);
			}
			if (endClass3 == null) {
				QuestionExtraValue evClass = wo.getQuestion().getExtraValue().get("commonQuestionType");
				if (evClass != null) {
					wo.setEndClass3(evClass.getValue());
				}
			} else {
				wo.setEndClass3(endClass3);
			}
			if (wo.getParent() != null) {
				WorkOrder woParent = wo.getParent();
				while (woParent.getParent() != null) {
					woParent.setStatus(2);
					woParent.setForwardFinishTime(currentDate);
					woParent.setFinishTime(currentDate);
					baseMgr.update(woParent);
					woParent = woParent.getParent();
				}

				if (woParent.getParent() == null) {

					WorkFlow wf = null;
					String questionType = woParent.getQuestion().getType().getName();
					if (questionType.equals("CommonQuestion")) {
						QuestionExtraValue ev = woParent.getQuestion().getExtraValue().get("commonQuestionType");
						if (ev != null && ev.getValue() != null) {
							CommonQuestionType cqt = (CommonQuestionType) baseMgr.get(CommonQuestionType.class, ev.getValue());
							wf = (WorkFlow) baseMgr.get(WorkFlow.class, cqt.getWorkFlowName());
						}

					} else {
						if (woParent.getQuestion().getType().getWorkFlowName() != null) {
							wf = (WorkFlow) baseMgr.get(WorkFlow.class, woParent.getQuestion().getType().getWorkFlowName());
						}
					}
					if (wf != null) {
						if (wf.getMustReturnMaster()) {
							// 必須返回主單
							question.setStatus(2);// finished
							baseMgr.update(question);
							woParent.setComment(note);
							woParent.setStatus(4);// returned
							sendReturnMail(woParent);
							baseMgr.update(woParent);
						} else {
							// 不需返回主單
							question.setStatus(2);// finished
							baseMgr.update(question);
							woParent.setComment(note);
							woParent.setStatus(2);// finished
							woParent.setFinishTime(new Date());
							baseMgr.update(woParent);
						}
					}
				}
				wo.setStatus(2);

			} else {
				question.setStatus(2);// finished
				baseMgr.update(question);
				wo.setStatus(2);

			}
			if (answer != null && answer.trim().length() > 0) {
				if (WorkOrderRule.answerNeedToBeApproved(wo)) {
					wo.setApproveGroup(WorkOrderRule.line2);
					wo.setApproveStatus(WorkOrder.APPROVE_STATUS.INIT.value());
					wo.setStatus(WorkOrder.STATUS.ANSWER_NEED_CONFIRM.value());
					answered(answer, showOnProductPage, currentDate, question, true, wo);
				} else {
					answered(answer, showOnProductPage, currentDate, question, false, wo);
				}

			}

			wo.setCompensation(compensation);
			baseMgr.update(wo);
			return wo;
		} catch (Exception e) {
			e.printStackTrace();
			System.out.println(e.fillInStackTrace());
		}
		return null;
	}

	@Override
	@Transactional(readOnly = false)
	public String approveOrder(String id, String approveComment) {
		String message = "";

		WorkOrder workOrder = (WorkOrder) baseMgr.get(WorkOrder.class, Long.parseLong(id));
		workOrder.setApproveComment(approveComment);
		workOrder.setApproveStatus(WorkOrder.APPROVE_STATUS.APPROVED.value());

		// 取出尚未通過的回答
		Object[] answers = baseMgr.queryByHql("from Answer a where a.question.id=? and isApproved!=?", new Object[] {
				workOrder.getDomainId(), new Boolean(true) });
		if (answers != null) {
			for (Object obj : answers) {
				Answer answer = (Answer) obj;
				answer.setIsApproved(true);
				baseMgr.update(answer);

				Question question = (Question) baseMgr.get(Question.class, workOrder.getDomainId());
				sendMailForAnswer(question, answer);

			}
		}
		if (workOrder.getStatus() == WorkOrder.STATUS.ANSWER_NEED_CONFIRM.value()) {
			Object[] childs = baseMgr.queryByHql("from WorkOrder where parent.id=?", new Object[] { workOrder.getId() });
			boolean isForwarded = false;
			if (childs != null && childs.length > 0) {
				for (Object obj : childs) {
					WorkOrder wo = (WorkOrder) obj;
					if (wo.getStatus() == WorkOrder.STATUS.NOT_ACTIVE.value()) {
						wo.setStatus(WorkOrder.STATUS.INIT.value());
						isForwarded = true;
					}
				}

			}
			if (isForwarded) {
				workOrder.setStatus(WorkOrder.STATUS.FORWARDED.value());
			} else {
				workOrder.setStatus(WorkOrder.STATUS.SUCCESS.value());
			}
		}

		// 檢查撿貨異常
		if (null != workOrder.getNode()) {
			if ("8ae4808e29100e910129107d908f0003".equals(workOrder.getNode().getId())) {
				String orderId = workOrder.getQuestion().getExtraValue().get("orderId").getValue();
				String typeId = workOrder.getQuestion().getExtraValue().get("commonQuestionType").getValue();
				CommonQuestionType cqt = (CommonQuestionType) baseMgr.get(CommonQuestionType.class, typeId);
				Orders order = (Orders) baseMgr.get(Orders.class, orderId);
				if (null == order) {
					workOrder.setApproveStatus(WorkOrder.APPROVE_STATUS.INIT.value());
					message = "此订单编号不存在，无法取消";
				} else if (!"25".equals(order.getOrderSt())) {
					workOrder.setApproveStatus(WorkOrder.APPROVE_STATUS.INIT.value());
					message = "此订单的状态已非出货处理中，无法取消";
				} else {

					// 檢查不重複申請撿貨異常取消。
					String sql = "select b.work_order_id from crm_question_ev a,crm_work_order b where a.question_id = b.domainid and  b.approvestatus='1' and b.node_id = '8ae4808e29100e910129107d908f0003' and a.name = 'orderId' and a.value = ?";
					List workOrders = jdbcTemplate.queryForList(sql, new Object[] { orderId });
					if (workOrders.size() == 0) {
						workOrder.setApproveTime(new Date());
						if (!StringUtils.isBlank(orderId)) {
							batchJobService.save("ShippingExceptionCancelOrder", "<root><orderId>" + orderId
									+ "</orderId><cancelType>" + cqt.getDescription() + "</cancelType></root>", null, orderId);
						}
						message = "工单已核可！！";
					} else {
						workOrder.setApproveStatus(WorkOrder.APPROVE_STATUS.INIT.value());
						message = "此订单已申请过检货异常";
					}
				}
				baseMgr.update(workOrder);

			} else {
				message = "工单已核可！！";
				// 设定审核时间
				workOrder.setApproveTime(new Date());
				baseMgr.update(workOrder);
				updateWorkOrderApprove(workOrder);
			}
		} else {
			message = "工单已核可！！";
			// 设定审核时间
			workOrder.setApproveTime(new Date());
			baseMgr.update(workOrder);
			updateWorkOrderApprove(workOrder);
		}

		if (workOrder.getApproveStatus() == WorkOrder.APPROVE_STATUS.APPROVED.value()) {
			forwardOrderNotice(workOrder);
		}
		return message;
	}

	private void updateWorkOrderApprove(WorkOrder workOrder) {
		if (workOrder.getApproveId() == null) {
			return;
		}
		WorkOrderApprove woa = (WorkOrderApprove) baseMgr.get(WorkOrderApprove.class, workOrder.getApproveId());
		woa.setApproveDate(workOrder.getApproveTime());
		woa.setApprover(workOrder.getApprover());
		woa.setApproveStatus(String.valueOf(workOrder.getApproveStatus()));

		woa.setApproveComment(workOrder.getApproveComment());
		baseMgr.update(woa);
	}

	@Override
	@Transactional(readOnly = false)
	public void rejectOrder(String id, String approveComment) {
		WorkOrder workOrder = (WorkOrder) baseMgr.get(WorkOrder.class, Long.parseLong(id));
		workOrder.setApproveComment(approveComment);
		workOrder.setApproveStatus(WorkOrder.APPROVE_STATUS.REJECT.value());

		if (workOrder.getStatus() != WorkOrder.STATUS.ANSWER_NEED_CONFIRM.value()) {
			workOrder.setStatus(WorkOrder.STATUS.SUCCESS.value());
			WorkOrder parent = workOrder.getParent();
			parent.setStatus(WorkOrder.STATUS.RETURNED.value());
			parent.setComment(approveComment);
			Date currentDate = new Date();
			parent.setForwardFinishTime(currentDate);
			baseMgr.update(parent);
		}
		// 设定审核时间
		workOrder.setApproveTime(new Date());
		baseMgr.update(workOrder);
		WorkOrderApprove woa = new WorkOrderApprove();
		woa.setApproveDate(workOrder.getApproveTime());
		woa.setApprover(workOrder.getApprover());
		woa.setApproveStatus(String.valueOf(workOrder.getApproveStatus()));
		woa.setWorkOrderId(workOrder.getId());
		woa.setApproveComment(workOrder.getApproveComment());
		baseMgr.save(woa);
	}

	@Override
	@Transactional(readOnly = false)
	public void cancelReturnProductApply(String id, String answer, String showOnProductPage, String workOrderId,
			String note, String returnId) {
		closeOrder(id, answer, showOnProductPage, workOrderId, note, WorkOrder.FINISH_TYPE.SELF.value(), null, null, null,
				null);
		ServiceOrders so = (ServiceOrders) baseMgr.get(ServiceOrders.class, returnId);
		if (!so.getOrderSt().equals("00")) {
			throw new RuntimeException("This service order is processing!");
		}
		so.setOrderSt("80");
		baseMgr.update(so);
		logService.save("WorkOrderService", "cancelReturnProductApply", so);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.yaodian100.crm.workorder.service.WorkOrderService#confirmReturnProductApply(java.lang.String,
	 * java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String)
	 */
	@Override
	public void confirmReturnProductApply(String id, String answer, String showOnProductPage, String workOrderId,
			String note, String returnId) {
		closeOrder(id, answer, showOnProductPage, workOrderId, note, WorkOrder.FINISH_TYPE.SELF.value(), null, null, null,
				null);
		ServiceOrders so = (ServiceOrders) baseMgr.get(ServiceOrders.class, returnId);
		if (!so.getOrderSt().equals("00")) {
			// 狀態不正確！
			throw new RuntimeException("This service order is processing!");
		}
		so.setOrderSt("10");
		Object[] sops = baseMgr.queryByHql("from ServiceOrderProduct where serviceId=?", new Object[] { returnId });
		baseMgr.update(so);
		List list = new ArrayList();
		for (int i = 0; i < sops.length; i++) {
			list.add(sops[i]);
		}
		so.setServiceOrderProducts(list);
		batchJobService.save(ServiceOrders.SERVICE_ORDER_BEAN.CREATE.getValue(), "<root>" + toXML(so) + "</root>", null, so
				.getServiceId());
		logService.save("WorkOrderService", "confirmReturnProductApply", so);
	}

	private String toXML(ServiceOrders serviceOrder) {

		String xml = null;
		try {
			ByteArrayOutputStream baos = new ByteArrayOutputStream();
			BeanWriter beanWriter = new BeanWriter(baos);
			beanWriter.enablePrettyPrint();
			beanWriter.write(serviceOrder);
			xml = baos.toString();
			beanWriter.flush();
			baos.flush();
			beanWriter.close();
			baos.close();
		} catch (Exception e) {
			e.printStackTrace();
			throw new RuntimeException(e);
		}
		return xml;

	}

	// public String getWorkOrderIdByOrderProductId(String orderProductId){
	// Object[] values=new Object[]{orderProductId};
	// Object[] sops=baseMgr.queryByHql("from ServiceOrderProduct where orderProdId=?", values);
	// String serviceOrderId=((ServiceOrderProduct)sops[0]).getServiceId();
	// //ServiceOrders so=(ServiceOrders)baseMgr.get(ServiceOrders.class, serviceOrderId);
	// String hql="from Question where question.extraValue['returnId'].value=?";
	//
	// }
	// public String getWorkOrderIdByOrderId(String orderId){
	//
	// }

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.yaodian100.crm.workorder.service.WorkOrderService#proxyOrder(java.lang.String, java.lang.String,
	 * java.lang.String)
	 */
	@Override
	@Transactional(readOnly = false)
	public WorkOrder proxyOrder(String workOrderId, String responser) {
		WorkOrder wo = (WorkOrder) baseMgr.get(WorkOrder.class, Long.valueOf(workOrderId));
		if (wo.getStatus() != WorkOrder.STATUS.INIT.value()) {
			return null;
		}
		this.closeOrder(wo.getDomainId(), null, "false", workOrderId, "自动结单 代结：" + responser, WorkOrder.FINISH_TYPE.PROXY
				.value(), null, null, null, null);
		WorkOrder currentWo = null;
		if (wo.getParent() != null) {
			currentWo = this.forwardOrder(wo.getParent(), wo.getComment(), responser, wo.getNode().getId(), wo.getPriority());
		} else {
			User owner = (User) baseMgr.get(User.class, responser);
			currentWo = this.createWorkOrder("SYSTEM", wo.getDomainId(), wo.getQuestion().getShortDesc(), false, owner);
			currentWo.setStartTime(new Date());
			currentWo.setFinishTime(currentWo.getStartTime());
			baseMgr.update(currentWo);
		}
		return currentWo;

	}

	@Override
	@Transactional(readOnly = false)
	public WorkOrder transferOrder(String workOrderId, String responser) {
		WorkOrder wo = (WorkOrder) baseMgr.get(WorkOrder.class, Long.valueOf(workOrderId));
		if (wo.getStatus() != WorkOrder.STATUS.INIT.value()) {
			return null;
		}
		this.closeOrder(wo.getDomainId(), null, "false", workOrderId, "自动结单 移转：" + responser,
				WorkOrder.FINISH_TYPE.TRANSFER.value(), null, null, null, null);
		WorkOrder currentWo = null;
		if (wo.getParent() != null) {
			currentWo = this.forwardOrder(wo.getParent(), wo.getComment(), responser, wo.getNode().getId(), wo.getPriority());
		} else {
			User owner = (User) baseMgr.get(User.class, responser);
			currentWo = this.createWorkOrder("SYSTEM", wo.getDomainId(), wo.getQuestion().getShortDesc(), false, owner);
			Object[] gus = baseMgr.queryByHql("from TaskGroupUser where user.username=?", new Object[] { responser });
			TaskGroupUser theTu = null;
			if (gus != null) {
				for (int i = 0; i < gus.length; i++) {
					TaskGroupUser tu = (TaskGroupUser) gus[i];
					if (tu.getDefaultGroup()) {
						theTu = tu;
					}
				}
				if (theTu == null && gus.length > 0) {
					theTu = (TaskGroupUser) gus[0];
				}
			}
			if (theTu != null) {
				currentWo.setResponseGroup(theTu.getTaskGroup().getId());
			}
			currentWo.setStartTime(new Date());
			currentWo.setFinishTime(currentWo.getStartTime());
			baseMgr.update(currentWo);
		}
		return currentWo;

	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.yaodian100.crm.workorder.service.WorkOrderService#closeOrderByOrderId(java.lang.String, java.lang.String)
	 */
	@Override
	@Transactional(readOnly = false)
	public String closeOrderForPayByProductArrive(String orderId, String responser) {
		// 检查工单
		Object[] evs = baseMgr.queryByHql("from QuestionExtraValue where name=? and value=?", new Object[] { "orderId",
				orderId });
		return closeOrderByBase(responser, evs, "PayByProductArrive");

	}

	private String closeOrderByBase(String responser, Object[] evs, String workOrderType) {
		String questionId = null;
		if (evs != null) {
			User user = (User) baseMgr.get(User.class, responser);
			for (Object obj : evs) {
				QuestionExtraValue ev = (QuestionExtraValue) obj;
				Object[] wos = baseMgr.queryByHql(
						"from WorkOrder where domainId=? and question.type.name=? and (responseGroup=? or responseGroup is null)",
						new Object[] { ev.getQuestion().getId(), workOrderType, user.getGroupName() });
				if (wos != null) {
					for (Object objwo : wos) {
						WorkOrder wo = (WorkOrder) objwo;
						if (wo.getStatus() != (WorkOrder.STATUS.INIT.value())) {
							continue;
						}
						questionId = wo.getDomainId();
						if (wo.getOwner() != null) {
							if (!wo.getOwner().equals(user)) {
								WorkOrder currentWo = this.proxyOrder(String.valueOf(wo.getId()), responser);
								this.closeOrder(currentWo.getDomainId(), null, "false", String.valueOf(currentWo.getId()), "自动结单",
										WorkOrder.FINISH_TYPE.SELF.value(), null, null, null, null);
							} else {
								this.closeOrder(wo.getDomainId(), null, "false", String.valueOf(wo.getId()), "自动结单",
										WorkOrder.FINISH_TYPE.SELF.value(), null, null, null, null);
							}
						} else {

							wo.setResponseGroup(user.getGroupName());
							wo.setOwner(user);
							this.closeOrder(wo.getDomainId(), null, "false", String.valueOf(wo.getId()), "自动结单",
									WorkOrder.FINISH_TYPE.SELF.value(), null, null, null, null);
						}
					}
				}
			}
		}
		return questionId;
	}

	@Override
	@Transactional(readOnly = false)
	public String closeOrderForReturnProductApply(String returnId, String responser) {
		// 检查工单
		Object[] evs = baseMgr.queryByHql("from QuestionExtraValue where name=? and value=?", new Object[] { "returnId",
				returnId });
		return closeOrderByBase(responser, evs, "ReturnProductApply");

	}

	@Override
	@Transactional(readOnly = false)
	public String closeOrderForPartialCancelOrder(String orderId, String responser) {
		// 检查工单
		Object[] evs = baseMgr.queryByHql("from QuestionExtraValue where name=? and value=?", new Object[] { "orderId",
				orderId });
		return closeOrderByBase(responser, evs, "PartialCancelOrder");

	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.yaodian100.crm.workorder.service.WorkOrderService#closeWorkOrderForOutOfStock()
	 */
	@Override
	@Transactional(readOnly = false)
	public void closeWorkOrderForOutOfStockOfDay(String day) {
		try {
			Object[] woObjs = baseMgr
					.queryByHql(
							"from WorkOrder where domainId in (select id from Question where type.name = ? and createdate < (sysdate- ?) ) and status = 0 ",
							new Object[] { "OutOfStock", day });
			WorkOrder wo = null;
			Map<String, WorkOrder> oIdMap = new HashMap<String, WorkOrder>();
			String oId;
			String note = "自动结单";
			String answer = null;
			String showOnProductPage = "false";
			Long orderCount = null;
			if (!ArrayUtils.isEmpty(woObjs) && woObjs.length > 0) {
				for (Object woObj : woObjs) {
					wo = (WorkOrder) woObj;
					// 取得订单编号
					oId = wo.getQuestion().getExtraValue().get("orderId").getValue();
					System.out.println("oId::" + oId);
					if (null != oId && StringUtils.isNotBlank(oId)) {
						// 检查订单是否存在
						orderCount = baseMgr.countByHql("from Orders where orderId = ? ", new Object[] { oId });
						if (orderCount.intValue() > 0) {
							oIdMap.put(oId, wo);
						}
					}
				}
				// 结单并取消订单
				if (MapUtils.isNotEmpty(oIdMap)) {
					for (WorkOrder woParam : oIdMap.values()) {
						cancelOrderAndCloseWo(woParam.getQuestion().getId(), answer, showOnProductPage, woParam.getId().toString(),
								note, WorkOrder.FINISH_TYPE.PROXY.value());
					}
				}
			}
		} catch (Exception e) {
			throw new CoreException("fail closeWorkOrderForOutOfStockOfDay");
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.yaodian100.crm.workorder.service.WorkOrderService#cancelOrderAndCloseWo()
	 */
	@Override
	@Transactional(readOnly = false)
	public void cancelOrderAndCloseWo(String id, String answer, String showOnProductPage, String workOrderId,
			String note, String finishType) {
		try {
			// String id, String answer, "false", workOrderId, note, WorkOrder.FINISH_TYPE.PROXY.value()) {
			closeOrder(id, answer, showOnProductPage, workOrderId, note, finishType, null, null, null, null);
			WorkOrder wo = (WorkOrder) baseMgr.get(WorkOrder.class, Long.valueOf(workOrderId));
			Object[] qevs = baseMgr.queryByHql("from QuestionExtraValue where question.id=? and attribute.name=?",
					new Object[] { wo.getDomainId(), "orderId" });
			QuestionExtraValue qev = (QuestionExtraValue) qevs[0];
			String orderId = qev.getValue();
			qevs = baseMgr.queryByHql("from QuestionExtraValue where question.id=? and attribute.name=?", new Object[] {
					wo.getDomainId(), "cancelReason" });
			qev = (QuestionExtraValue) qevs[0];
			String cancelReason = qev.getValue();
			if (!StringUtils.isBlank(orderId)) {
				sendOutOfStockMail(wo, orderId);// 发送断货通知信,簡訊
				batchJobService.save("ShippingExceptionCancelOrder", "<root><orderId>" + orderId + "</orderId><cancelType>"
						+ cancelReason + "</cancelType></root>", null, orderId);
			}
		} catch (Exception e) {
			throw new CoreException("fail cancelOrderAndCloseWo");
		}
	}

	@Transactional(readOnly = false)
	private void sendOutOfStockMail(WorkOrder wo, String orderId) {
		// 发送断货通知信
		Object[] orders = baseMgr.queryByHql("from Orders where orderId = ? ", new Object[] { orderId });
		if (null != orders && orders.length > 0) {
			Orders order = (Orders) orders[0];
			Product product = null;
			List<Product> products = new ArrayList<Product>();
			for (OrderProduct op : order.getOrderProduct()) {
				product = (Product) baseMgr.get(Product.class, op.getProdId());
				products.add(product);
			}
			Map<String, Object> mailContentParameters = new HashMap<String, Object>();
			mailContentParameters.put("order", order);
			mailContentParameters.put("products", products);
			mailContentParameters.put("orderDate", FastDateFormat.getInstance(EcConstant.PATTERN_TIMESTAMP_HH_MM).format(
					order.getOrderDt()));
			mailContentParameters.put("basehref", "http://" + order.getDomainSrc());
			Mail stockMail = velocityService.formatToMail("outOfStockMail", mailContentParameters);
			stockMail.addTo(order.getMemberName(), order.getReceiverEmail());
			// stockMail.addTo("feeling", "feeling.wang@yaodian100.com");
			stockMail.setFrom(envParameters.getEmailFromCs());
			mailService.save(stockMail);
			// 发送简讯
			StringBuffer msg = new StringBuffer();
			msg.append("亲爱的耀点100用户，您订购的商品已无货，因多次无法连系到您，为避免不必要的等待造成额外不便，我们很抱歉的通知您订单").append(orderId).append(
					"无法成立，相应的退款作业也会尽快进行。若有任何疑问，请致电客服4001-168-100。再次感谢您对耀点100的支持。【耀点100】");
			smsService.sendSms(order.getReceiverMobile(), msg.toString(), order.getOrderId());
		}
	}

	@Override
	public String chkServiceOrderByOrderId(String orderId) {
		if (StringUtils.isBlank(orderId)) {
			return "订单编号不可为空.";
		} else {
			Orders order = (Orders) baseMgr.get(Orders.class, orderId);
			if (null == order) {
				return "订单" + orderId + "不存在.";
			} else {
				Long num = baseMgr.countByHql("from ServiceOrders where orderId = ? and orderSt <> '80' ",
						new Object[] { orderId });
				if (num.intValue() > 0) {
					return "订单" + orderId + "已有SR单, 无法变更状态.";
				} else {
					return "true";
				}
			}
		}
	}

	@Override
	@Transactional(readOnly = false)
	public String updOrderStatusTo30ByOrderId(String orderId) {
		String result = chkServiceOrderByOrderId(orderId);
		if ("true".equals(result)) {
			try {
				// 检查订单付款方式
				Orders order = (Orders) baseMgr.get(Orders.class, orderId);
				if ("30".equals(order.getOrderSt())) {// 若订单状态为已发货，则直接return true
					return "true";
				} else {
					if (Arrays.asList("30", "60").contains(order.getPaymentTp())) {// cod
						baseMgr.executeHql(
								"update Orders set orderSt= '30' , cash = 0 ,paymentSt = '00' ,paymentDt = null where orderId = ?",
								new Object[] { orderId });
					} else {
						baseMgr.executeHql("update Orders set orderSt= '30' where orderId = ?", new Object[] { orderId });
					}
					baseMgr.executeHql(
							"update OrderProduct set logisticFinalDt= null ,logisticSt = '30',prodStatus = 0 where orderId = ?",
							new Object[] { orderId });
					return "true";
				}
			} catch (Exception e) {
				return e.toString();
			}
		} else {
			return result;
		}
	}

	@Override
	public String chkServiceOrderByServiceId(String serviceId) {
		if (StringUtils.isBlank(serviceId)) {
			return "SR单编号不可为空.";
		} else {
			ServiceOrders serviceOrder = (ServiceOrders) baseMgr.get(ServiceOrders.class, serviceId);
			if (null == serviceOrder) {
				return "SR单" + serviceId + "不存在.";
			} else {
				if (2 != serviceOrder.getSrcType()) {
					return serviceId + "不是换货单.";
				} else {
					if (Arrays.asList("90", "20").contains(serviceOrder.getOrderSt())) {
						return "true";
					} else {
						return "SR单" + serviceId + "状态错误.";
					}
				}
			}
		}
	}

	@Override
	@Transactional(readOnly = false)
	public String updServiceOrderStatusTo20ByServiceId(String serviceId) {
		String result = chkServiceOrderByServiceId(serviceId);
		if ("true".equals(result)) {
			try {
				// 检查服务单状态
				ServiceOrders serviceOrder = (ServiceOrders) baseMgr.get(ServiceOrders.class, serviceId);
				if ("20".equals(serviceOrder.getOrderSt())) {
					return "true";
				} else {
					baseMgr.executeHql("update ServiceOrders set orderSt= '20' where serviceId = ?", new Object[] { serviceId });
					return "true";
				}
			} catch (Exception e) {
				return e.toString();
			}
		} else {
			return result;
		}
	}

	@Override
	@Transactional(readOnly = false)
	public WorkOrder newOrder(Long workOrderId, String responser) {
		WorkOrder wo = (WorkOrder) baseMgr.get(WorkOrder.class, workOrderId);
		// 檢查問題單是否已結束
		if (wo.getQuestion().getStatus() == WorkOrder.STATUS.SUCCESS.value()) {
			// 已結單
			throw new RuntimeException("此工单相关的问题已结束");
		} else {
			// 未結單
			// 檢查是否可成立工單
			if (wo.getStatus() == WorkOrder.STATUS.INIT.value()) {
				// 可建立工單
				WorkOrder newWo = this.proxyOrder(String.valueOf(workOrderId), responser);
				return newWo;
			} else {
				throw new RuntimeException("此工单无法再建工单");
			}
		}
	}

	@Override
	@Transactional(readOnly = false)
	public void batchAssign(String[] workOrderIds, String taskGroupId, String[] userIds, String[] assignCounts) {

		int userAt = 0;
		String userId = null;
		String assignCount = "9999";
		int ac = 0;
		for (int i = 0; i < workOrderIds.length; i++) {
			String woId = workOrderIds[i];
			WorkOrder wo = (WorkOrder) baseMgr.get(WorkOrder.class, Long.valueOf(woId));

			userId = userIds[userAt];

			if (assignCounts != null) {
				assignCount = assignCounts[userAt];
				if (assignCount.equals("")) {
					assignCount = "0";
				}
			}
			ac = Integer.valueOf(assignCount);
			if (i > 0) {
				if (ac <= i) {
					userAt++;
					if (userAt > userIds.length - 1) {
						break;
					} else {
						userId = userIds[userAt];

						if (assignCounts != null) {
							assignCount = assignCounts[userAt];
							if (assignCount.equals("")) {
								assignCount = "0";
							}
						}
						ac = Integer.valueOf(assignCount);
					}
				}
			}
			if (wo.getStatus() == WorkOrder.STATUS.INIT.value()) {
				if (wo.getOwner() != null) {
					if (!wo.getOwner().getUsername().equals(AdminHelper.getUser().getUsername())) {
						// 移转
						this.transferOrder(String.valueOf(wo.getId()), userId);
					}
				} else {
					// 取单
					get(wo.getId(), userId);
				}
			}

		}
	}

	@Override
	@Transactional(readOnly = false)
	public WorkOrder get(Long workOrderId, String username) {
		WorkOrder wo = (WorkOrder) baseMgr.get(WorkOrder.class, workOrderId);
		User user = (User) baseMgr.get(User.class, username);
		wo.setOwner(user);
		Object[] gus = baseMgr.queryByHql("from TaskGroupUser where user.username=?", new Object[] { username });
		TaskGroupUser theTu = null;
		if (gus != null) {
			for (int i = 0; i < gus.length; i++) {
				TaskGroupUser tu = (TaskGroupUser) gus[i];
				if (tu.getDefaultGroup()) {
					theTu = tu;
				}
			}
			if (theTu == null) {
				theTu = (TaskGroupUser) gus[0];
			}
		}
		if (theTu != null) {
			wo.setResponseGroup(theTu.getTaskGroup().getId());
		}
		wo.setStartTime(new Date());
		baseMgr.update(wo);
		return wo;
	}
}
